﻿#include "XModbusCoilsDisc.h"
#include "XMemory.h"
#include "XByteArray.h"
#include "XModbusFrame.h"
#include "XModbus.h"
#include "XBitArray.h"
#include <string.h>
/*
* @brief  一个字节中按偏移量设置一个比特位
* @param  ByteBuff:uint8_t* 类型 指向要操作的字节
* @param  Offset:偏移量(0~7)
* @param  State:要设置的状态(0或1)
* @retval
*/
#define XMODBUS_UINT8_SET_BITS(ByteBuff,Offset,State) (*(ByteBuff)=((State<<Offset)|(*(ByteBuff))))
/*
* @brief  一个字节中按偏移量查看一个比特位
* @param  ByteBuff:uint8_t* 类型 指向要查看的字节
* @param  Offset:偏移量(0~7)
* @retval 状态(0或1)
*/
#define XMODBUS_UINT8_GET_BITS(ByteBuff,Offset) (((*(ByteBuff))>>Offset)&0x1) 

XModbusCoilsDisc* XModbusCoilsDisc_create(uint16_t count)
{
    if (count == 0)
        return NULL;
    //uint16_t size = (count % 8 == 0) ? (count / 8) : ((count / 8) + 1);
    XModbusCoilsDisc* ptr = XMemory_malloc(sizeof(XModbusCoilsDisc));
    XModbusDeviceObject_init(ptr);
    ptr->count = count;
    ptr->parent.data = XBitArray_create(count);
    XBitArray_setBitOrder(ptr->parent.data, XBIT_ORDER_LSB_FIRST);
    return ptr;
}

void XModbusCoilsDisc_delete(XModbusCoilsDisc* pRegHandler)
{
    if (pRegHandler)
    {
        if (pRegHandler->parent.data)
            XBitArray_delete_base(pRegHandler->parent.data);
        XMemory_free(pRegHandler);
    }
}
bool XModbusCoilsDisc_write_bool(XModbusCoilsDisc* pRegHandler, uint16_t address, bool state)
{
    if (!pRegHandler || !pRegHandler->parent.data || address >= pRegHandler->count)
        return false;
    return XBitArray_setBit(pRegHandler->parent.data,address,state);
}
// 定义MIN宏
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
bool XModbusCoilsDisc_write(XModbusCoilsDisc* pRegHandler, uint16_t address, uint16_t count, const uint8_t* writeArray)
{
    if (!pRegHandler || !pRegHandler->parent.data || !writeArray || !count)
        return false;
   return  XBitArray_writeBits(pRegHandler->parent.data, address, count, writeArray, (count + 7)/8);
}

bool XModbusCoilsDisc_read(XModbusCoilsDisc* pRegHandler, uint16_t address, uint16_t count, uint8_t* readArray, uint16_t readArraySize)
{
    if (!pRegHandler || !pRegHandler->parent.data || !readArray || !count)
        return false;
    return XBitArray_readBits(pRegHandler->parent.data,address,count,readArray,readArraySize);
}

bool XModbusCoilsDisc_at(XModbusCoilsDisc* pRegHandler, uint16_t regAddress)
{
    if (!pRegHandler || !pRegHandler->parent.data || regAddress >= pRegHandler->count)
        return false;
    return XBitArray_at(pRegHandler->parent.data, regAddress);
}

void XModbusCoilsDisc_0x01_RTU_masterRecvHandCb(XModbusRecvMatch* math, XModbus* modbus, XModbusFrame* recvFrame, XModbusDeviceObject* device)
{
    if (modbus == NULL || recvFrame == NULL || device == NULL)
        return;
    //printf("处理主站接收信息\n");
    XModbusCoilsDisc* coilsFunc = device;
    XModbusFrameRTU* rtu = (XModbusFrameRTU*)recvFrame->data;
    if (rtu == NULL)
        return;
    //模板并不完整,返回帧并没有告诉有几个线圈
    if (rtu->data != NULL)
    {
        //if (XModbusCoilsDisc_write(coilsFunc, rtu->regAddress, rtu->regCount, XContainerDataPtr(rtu->data)) && device->cb != NULL)
          //  device->cb(device->userData);
       /* uint8_t* d = XContainerDataPtr(rtu->data);
        printf("当前:code:%d  data:%d\n",math->code,*d);*/
    }
}

void XModbusCoilsDisc_0x02_RTU_masterRecvHandCb(XModbusRecvMatch* math, XModbus* modbus, XModbusFrame* recvFrame, XModbusDeviceObject* device)
{
    XModbusCoilsDisc_0x01_RTU_masterRecvHandCb(math,modbus,recvFrame, device);
}

void XModbusCoilsDisc_0x01_RTU_slaveRecvHandCb(XModbusRecvMatch* math, XModbus* modbus, XModbusFrame* recvFrame, XModbusDeviceObject* device)
{
    if (modbus == NULL || recvFrame == NULL || device == NULL)
        return;
    XModbusCoilsDisc* coilsFunc = device;
    XModbusFrameRTU* rtu = (XModbusFrameRTU*)recvFrame->data;
    XModbusFrame* sendFrame = XModbusFrame_create(modbus->m_mode);
    XVector* data = coilsFunc->parent.data;//寄存器数据
    if ((((rtu->regAddress) + (rtu->coilsCount)) <= coilsFunc->count) && ((rtu->coilsCount) > 0))
    {
        //void* readStart = XVector_at_base(data, rtu->coilsAddress);//寄存器数据缓冲区
        size_t buffSize = rtu->coilsCount / 8 + 1;
        uint8_t* buff = XMemory_malloc(buffSize);
        if(XModbusCoilsDisc_read(device, rtu->address, rtu->coilsCount, buff, buffSize))
            XModbusFrameRTU_setFrameData_0x01_reply(sendFrame, rtu->address, buff, rtu->coilsCount);
        else
            XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_READ_COILS, MB_EX_ILLEGAL_DATA_ADDRESS);
        XMemory_free(buff);
    }
    else
    {//参数有问题
        XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_READ_COILS, MB_EX_ILLEGAL_DATA_ADDRESS);
    }
    XModbus_sendData_base(modbus, sendFrame);
}

void XModbusCoilsDisc_0x02_RTU_slaveRecvHandCb(XModbusRecvMatch* math, XModbus* modbus, XModbusFrame* recvFrame, XModbusDeviceObject* device)
{
    if (modbus == NULL || recvFrame == NULL || device == NULL)
        return;
    XModbusCoilsDisc* coilsFunc = device;
    XModbusFrameRTU* rtu = (XModbusFrameRTU*)recvFrame->data;
    XModbusFrame* sendFrame = XModbusFrame_create(modbus->m_mode);
    XVector* data = coilsFunc->parent.data;//寄存器数据
    if ((((rtu->regAddress) + (rtu->coilsCount)) <= coilsFunc->count) && ((rtu->coilsCount) > 0))
    {
        //void* readStart = XVector_at_base(data, rtu->coilsAddress);//寄存器数据缓冲区
        size_t buffSize = rtu->coilsCount / 8 + 1;
        uint8_t* buff = XMemory_malloc(buffSize);
        if (XModbusCoilsDisc_read(device, rtu->address, rtu->coilsCount, buff, buffSize))
            XModbusFrameRTU_setFrameData_0x02_reply(sendFrame, rtu->address, buff, rtu->coilsCount);
        else
            XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_READ_DISCRETE_INPUTS, MB_EX_ILLEGAL_DATA_ADDRESS);
        XMemory_free(buff);
    }
    else
    {//参数有问题
        XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_READ_DISCRETE_INPUTS, MB_EX_ILLEGAL_DATA_ADDRESS);
    }
    XModbus_sendData_base(modbus, sendFrame);
}

void XModbusCoilsDisc_0x05_RTU_slaveRecvHandCb(XModbusRecvMatch* math, XModbus* modbus, XModbusFrame* recvFrame, XModbusDeviceObject* device)
{
    if (modbus == NULL || recvFrame == NULL || device == NULL)
        return;
    XModbusCoilsDisc* coilsFunc = device;
    XModbusFrameRTU* rtu = (XModbusFrameRTU*)recvFrame->data;
    if (rtu == NULL)
        return;

    XByteArray* sendFrame = XByteArray_create(0);
    if (rtu->data != NULL)
    {
        uint8_t buff;
        uint16_t cmp = XMODBUS_COILS_STATE_ON;
        if(memcmp(XContainerDataPtr(rtu->data),&cmp,2)==0)
            XMODBUS_UINT8_SET_BITS(&buff,0,true);
        else
            XMODBUS_UINT8_SET_BITS(&buff, 0, false);
        if (XModbusCoilsDisc_write(coilsFunc, rtu->regAddress, 1,&buff))
        {//写入成功 将数据帧再次发送回去
            XVector_swap_base(recvFrame->frameData, sendFrame);
        }
        else
        {
            XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_WRITE_SINGLE_COIL, MB_EX_SLAVE_DEVICE_FAILURE);//写入失败设备故障
        }
    }
    else
    {//参数有问题
        XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_WRITE_SINGLE_COIL, MB_EX_ILLEGAL_DATA_ADDRESS);
    }
    XModbus_sendData_base(modbus, sendFrame);
}

void XModbusCoilsDisc_0x0F_RTU_slaveRecvHandCb(XModbusRecvMatch* math, XModbus* modbus, XModbusFrame* recvFrame, XModbusDeviceObject* device)
{
    if (modbus == NULL || recvFrame == NULL || device == NULL)
        return;
    XModbusCoilsDisc* coilsFunc = device;
    XModbusFrameRTU* rtu = (XModbusFrameRTU*)recvFrame->data;
    if (rtu == NULL)
        return;
    //获取寄存器地址
    uint16_t coilsAddress = rtu->coilsAddress;
    //寄存器数量
    uint16_t coilsCount = rtu->coilsCount;

    XModbusFrame* sendFrame = XModbusFrame_create(modbus->m_mode);
    if (rtu->data != NULL)
    {
        if(XModbusCoilsDisc_write(coilsFunc, coilsAddress, coilsCount,XContainerDataPtr(rtu->data)))
            XModbusFrameRTU_setFrameData_0x0F_reply(sendFrame, rtu->address, coilsAddress, coilsCount);
        else
            XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_WRITE_MULTIPLE_COILS, MB_EX_ILLEGAL_DATA_ADDRESS);
    }
    else
    {//参数有问题
        XModbusFrameRTU_setFrameData_0x8X_reply(sendFrame, rtu->address, MB_FUNC_WRITE_MULTIPLE_COILS, MB_EX_ILLEGAL_DATA_ADDRESS);
    }
    XModbus_sendData_base(modbus, sendFrame);
    //printf("写多个线圈\n");
}
